import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

/**
 * La classe MySQLConnection consente la connessione al database e la creazione
 * degli oggetti per la gestione ed esecuzione delle query.
 * 
 */
public class MySQLConnection {
	private Connection connection;
	private Statement statement;
	private DataSource ds;

	/**
	 * Costruttore di default che consente la creazione di una nuova connessione
	 * al DB. L’oggetto viene creato tramite Tomcat in modo da sfruttare il pool
	 * di connessioni gestito da quest’ultimo.
	 * 
	 * @throws SQLException
	 */
	public MySQLConnection() throws SQLException {
		Context initCtx;
		try {
			initCtx = new InitialContext();
			Context envCtx = (Context) initCtx.lookup("java:comp/env");
			ds = (DataSource) envCtx.lookup("jdbc/MiviaMovieDB");
			connection = ds.getConnection();
			statement = connection.createStatement();
		} catch (NamingException e) {
			e.printStackTrace();
		}

	}

	/**
	 * Costruttore che consente la connessione al DB in locale. Questa modalità
	 * non deve essere utilizzata dalla Web Application in esecuzione su Tomcat
	 * ma può essere utilizzata per eseguire test in locale.
	 * 
	 * @param user
	 *            Utente con cui autenticarsi al DB
	 * @param password
	 *            Password di autenticazione
	 * @param db
	 *            Nome del database
	 * @throws SQLException
	 */
	public MySQLConnection(String user, String password, String db)
			throws SQLException {
		// carico il driver di MySQL
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// setup the connection with the DB.
		connection = DriverManager.getConnection("jdbc:mysql://localhost/" + db
				+ "?" + "user=" + user + "&password=" + password);
		statement = connection.createStatement();

		// statements allow to issue SQL queries to the database
	}

	/**
	 * Consente di eseguire una query di inserimento, cancellazione o
	 * aggiornamento sul database.
	 * 
	 * @param query
	 *            Query da eseguire
	 * @return numero di righe che sono state modificate.
	 * @throws SQLException
	 */
	public int executeUpdate(String query) throws SQLException {
		if (statement != null) {
			return statement.executeUpdate(query);
		} else {
			return -1;
		}
	}

	/**
	 * Consente di eseguire una query di selezione sul DB. Restituisce un
	 * oggetto contenente il risultato della query.
	 * 
	 * @param query
	 *            Query di selezione da eseguire
	 * @return Risultato della query
	 * @throws SQLException
	 */
	public ResultSet executeQuery(String query) throws SQLException {
		if (statement != null) {
			return statement.executeQuery(query);
		} else {
			return null;
		}

	}

	/**
	 * Crea un PreparedStatement che consente di inviare query parametrizzate al
	 * database.
	 * 
	 * @param parametrizedQuery
	 *            Query parametrizzata da eseguire
	 * @return Oggetto per gestire la query parametrizzata
	 * @throws SQLException
	 */
	public PreparedStatement createPreparedStatement(String parametrizedQuery)
			throws SQLException {
		if (connection != null)
			return connection.prepareStatement(parametrizedQuery);
		else
			return null;
	}

	/**
	 * Consente la chiusura della connessione al DB
	 */
	public void closeConnection() {
		try {
			if (statement != null) {
				statement.close();
				statement = null;
			}
			if (connection != null) {
				connection.close();
				connection = null;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Metodo invocato dal garbage collector prima della distruzione
	 * dell'oggetto. Consente di controllare se la connessione è stata chiusa
	 * altrimenti la chiude. Bisogna comunque gestire la connessione in modo
	 * opportuno e non fare affidamento su questo metodo per la chiusura delle
	 * connessioni.
	 */
	@Override
	protected void finalize() {
		try {
			closeConnection();
		} finally {
			try {
				super.finalize();
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}

}
